import knex from '../db/sql'
import UserController from './user.controller'
import AdminController from './admin.controller';
import {Context, MetheodType, Next} from 'TYPE';
import {validateBody, validateQuery} from '../parameter_m';
import {userDB} from '../db/sqltable/user.db';
import {postDB} from '../db/sqltable/post.db';
import {subareaDB} from '../db/sqltable/subarea.db';
import {userPostRelationDB} from '../db/sqltable/user_post_relation.db';
import {notificationDB} from '../db/sqltable/notification.db';
import {topicDB} from '../db/sqltable/topic.db';

export default class PostController {

    @validateQuery({
        pid: 'int?',
        ppid: 'int?',
        author: 'int?',
        paged: 'int?',
        posts_per_page: {type: 'int', required: false, max: 1000},
        subarea: 'int?',
        topic: 'int?',
        onlyTopic: 'int?',
        'relationships[]': {type: 'array', required: false, max: 10},
        key: {type: 'string', required: false, max: 128}
    })
    static async getPosts(ctx: Context, next: Next) {
        let {pid, ppid, author, paged, posts_per_page, subarea, topic, onlyTopic, key} = ctx.validatedParams

        paged ??= 1
        posts_per_page ??= 10
        let relationships = ctx.validatedParams['relationships[]'] ?? []
        if (key) {
            key = postDB.processSearchKey(key)
        }
        let posts = pid ? {total: 1, list: [await postDB.getPostById(pid)]} : await postDB.getPosts(
            {paged, posts_per_page, topic, subarea, author, ppid, onlyTopic: onlyTopic ? true : false, searchKey: key})
        // if has pid, check if all conditions are met.
        if (pid && posts.list.length) {
            let nopass = false

            if (subarea) {
                if (posts.list[0].subarea != subarea)
                    nopass = true
            }
            if (topic)
                if (posts.list[0].topic != topic)
                    nopass = true
            if (nopass) {
                ctx.cd = 1
                ctx.msg = "无帖子"
                next()
                return
            }
        }
        relationships = relationships.filter((v: string) => {return userPostRelationDB.relationships.includes(v)})
        for (let post of posts.list as any) {
            post = await PostController.assemblePost(post, relationships);
        }
        if (!posts || !posts.list.length) {
            ctx.cd = 1
            ctx.msg = "无帖子"
        } else {
            ctx.cd = 0
            ctx.msg = "查找成功"
            ctx.return = posts
        }
        next()
    }
    @validateQuery({
        uid: 'int',
        paged: 'int?',
        posts_per_page: {type: 'int', required: false, max: 1000},
        subarea: 'int?',
        topic: 'int?',
        'relationships[]': {type: 'array', required: false, max: 10},
        byRelationship: 'string',
    })
    static async getPostsByRelationship(ctx: Context, next: Next) {
        let {uid, paged, posts_per_page, subarea, topic, byRelationship} = ctx.validatedParams

        paged ??= 1
        posts_per_page ??= 10
        let relationships = ctx.validatedParams['relationships[]'] ?? []
        relationships = relationships.filter((v: string) => {return userPostRelationDB.relationships.includes(v)})
        let posts = {total: 0, list: []} as any
        let ps = await userPostRelationDB.queryRelationsByUid(uid, byRelationship, paged, posts_per_page)
        posts.total = await userPostRelationDB.queryRelationsCountByUid(uid, byRelationship)
        posts.list = []
        for (let p of ps) {
            posts.list.push(await postDB.getPostById(Number(p)))
        }
        for (let post of posts.list as any) {
            post = await PostController.assemblePost(post, relationships);
        }
        if (!posts || !posts.list.length) {
            ctx.cd = 1
            ctx.msg = "无帖子"
        } else {
            ctx.cd = 0
            ctx.msg = "查找成功"
            ctx.return = posts
        }
        next()
    }

    @validateQuery({
        subareaid: 'int',
    })
    static async getSubarea(ctx: Context, next: Next) {
        let {subareaid} = ctx.validatedParams

        let subarea = await subareaDB.getSubareaById(subareaid)
        if (!subarea) {
            ctx.cd = 1
            ctx.msg = "无分区"
        } else {
            ctx.cd = 0
            ctx.msg = "查找成功"
            ctx.return = subarea
        }
        next()
    }
    @validateQuery({
        paged: 'int?',
        posts_per_page: {type: 'int', required: false, max: 1000},
        type: {type: 'int', required: false, min: 1, max: 2}
    })
    static async getSubareas(ctx: Context, next: Next) {
        let {paged, posts_per_page, type} = ctx.validatedParams
        if (!type) {
            type = 1
        }
        let subareas = await subareaDB.getSubareas(type, paged, posts_per_page)
        if (!subareas) {
            ctx.cd = 1
            ctx.msg = "无分区"
        } else {
            ctx.cd = 0
            ctx.msg = "查找成功"
            ctx.return = subareas
        }
        next()
    }

    @validateQuery({
        paged: 'int?',
        posts_per_page: {type: 'int', required: false, max: 1000},
        subarea: 'int?',
        'relationships[]': {type: 'array', required: false, max: 10},
        sortby: 'string?',
        type: 'number'
    })
    static async getTopics(ctx: Context, next: Next) {
        let {paged, posts_per_page, subarea, type, sortby} = ctx.validatedParams
        const sortbylist = ['active_time', 'create_time', 'views']
        if (!sortbylist.includes(sortby)) sortby = 'active_time'
        paged ??= 1
        posts_per_page ??= 10
        let relationships = ctx.validatedParams['relationships[]'] ?? []

        let posts = await postDB.getTopics(paged, posts_per_page, subarea, type, sortby)

        // if has pid, check if all conditions are fit.

        relationships = relationships.filter((v: string) => {return userPostRelationDB.relationships.includes(v)})

        for (let post of posts.list as any[]) {
            if (typeof post === 'string')
                post = JSON.parse(post)
            this.assemblePost(post, relationships)
            post.topic = await topicDB.getTopicById(post.topic);
            post.subarea = await subareaDB.getSubareaById(post.topic.sid);
            for (const r of relationships) {
                (post as any)[r] = await userPostRelationDB.queryRelationsByPid(post.pid, r, 1, 10)
            }
            await postDB.countPostViews(post)
        }
        if (!posts || !posts?.list?.length) {
            ctx.cd = 1
            ctx.msg = "无主题"
        } else {
            ctx.cd = 0
            ctx.msg = "查找成功"
            ctx.return = posts
        }
        next()
    }
    @validateQuery({
        tid: 'int?',
        ppid: 'int?',
        onlyPid: 'int?',
        paged: 'int?',
        posts_per_page: {type: 'int', required: false, max: 1000},
        onlyAuthor: 'int?',
        'relationships[]': {type: 'array', required: false, max: 10},
        sortby: 'string?',
        direction: 'string?'
    })
    static async getSubPosts(ctx: Context, next: Next) {
        let {tid, ppid, paged, onlyPid, posts_per_page, onlyAuthor, sortby, direction} = ctx.validatedParams

        console.log(direction);
        let subarea = null
        let topic = null
        let post = null
        if (tid) {
            topic = await topicDB.getTopicById(tid) as any
            if (!topic) {
                ctx.cd = 1
                ctx.msg = "无主题"
                await next()
                return
            }
            subarea = await subareaDB.getSubareaById(topic.sid)
            if (!subarea) {
                ctx.cd = 1
                ctx.msg = "无主题"
                await next()
                return
            }
            topic.subarea = subarea

            post = await postDB.getPostById(topic.pid)
        } else {
            post = await postDB.getPostById(ppid)
        }
        if (!post) {
            ctx.cd = 1
            ctx.msg = "无主贴"
            await next()
            return
        }
        const sortbyList = ['create_time', 'modify_time', 'active_time']
        if (!sortbyList.includes(sortby)) {
            sortby = 'create_time'
        }
        if (direction) {
            const directionList = ['DESC', 'ASC']
            if (!directionList.includes(direction)) {
                direction = 'DESC'
            }
        }
        ctx.cd = 0
        ctx.msg = "查找成功"
        const viewsHash = '' + (ctx.session.user?.uid ?? ctx.request.ip)
            + (Date.now() / 600000 >> 0) // 十分钟记一次父帖子的浏览量(uv)
        postDB.addPostViews(post.pid, viewsHash)
        if (onlyPid) {
            let subPostsList = await postDB.getSubPostsPidList(post.pid, sortby, direction)
            ctx.return = {subPostsList}
            await next()
            return
        }

        paged ??= 1
        posts_per_page ??= 10

        let relationships = ctx.validatedParams['relationships[]'] ?? []
        relationships = relationships.filter((v: string) => {return userPostRelationDB.relationships.includes(v)})
        post = await PostController.assemblePost(post, relationships)

        let subPosts = await postDB.getPosts({paged, posts_per_page, author: onlyAuthor ? post.author : null, ppid: post.pid, sortby, direction})

        await postDB.countPostViews(post)

        // if has pid, check if all conditions are met.
        for (let post of subPosts.list) {
            post = await PostController.assemblePost(post, relationships);
        }
        ctx.return = {post, subPosts, topic}

        next()
    }

    private static async assemblePost(post: any, relationships: any) {
        if (typeof post === 'string')
            post = JSON.parse(post);
        post.user = await userDB.getUserById(post.author);
        for (const r of relationships) {
            (post as any)[r] = await userPostRelationDB.queryRelationsByPid(post.pid, r, 1, 10);
            (post as any)[r + '_count'] = await userPostRelationDB.queryRelationsCountByPid(post.pid, r);
        }

        return post;
    }

    @UserController.checkLogin
    @validateBody({
        title: 'string?',
        content: 'string',
        subarea: 'int',
        thumbnail: 'string?'
    })
    static async post(ctx: Context, next: Next) {
        // console.log("???");
        let {title, content, subarea, thumbnail} = ctx.validatedParams
        let sa = await subareaDB.getSubareaById(subarea)

        if (!sa) {
            ctx.cd = 1
            ctx.msg = "无此分区"
            await next()
            return
        }
        ctx.cd = 1
        ctx.msg = "内部错误"
        ctx.return = {}

        const trx = await knex.transaction();
        let type = 1
        if (sa.type == 1 || sa.type == 2) {
            await trx('topics').insert({name: title, sid: subarea, thumbnail}, 'id').then(res => {
                if (res.length) {
                    ctx.return.topicid = res[0]
                }
            }).catch((res) => {
                trx.rollback()
                console.log(res);
            })
        }
        await trx('posts').insert({content, subarea, author: ctx.user.uid, status: 0, type, topic: ctx.return.topicid}, 'pid').then(res => {
            if (res.length) {
                ctx.cd = 0
                ctx.msg = "上传成功"
                ctx.return.postid = res[0]
            }
        }).catch((res) => {
            trx.rollback()
            console.log(res);
        }).then(trx.commit)

        if (ctx.return.topicid)
            topicDB.loadTopicById(ctx.return.topicid as any)
        if (ctx.return.postid)
            postDB.loadPostByid(ctx.return.postid as any)

        await next()
    }
    @UserController.checkLogin
    @validateBody({
        pid: 'int',
        title: 'string?',
        content: 'string'
    })
    static async comment(ctx: Context, next: Next) {
        let {title, content, pid: parent_pid} = ctx.validatedParams

        let post = await postDB.getPostById(parent_pid)
        // TODO Check content and title

        if (!post) {
            ctx.cd = 1
            ctx.msg = "无post"
        } else {
            let postType = Number(post.type) + 1

            if (postType > 3 || postType < 2) {
                ctx.cd = 1
                ctx.msg = "回复错误"
                await next()
                return
            }

            await knex('posts').insert({title, ppid: parent_pid, content, subarea: post.subarea, author: ctx.user.uid, status: 0, type: postType}, 'pid').then(res => {
                if (res.length) {
                    ctx.cd = 0
                    ctx.msg = "上传成功"
                    ctx.return = res[0]
                    // if (postType == 3)
                    //     postDB.appendOneSubComment(res[0] as any)
                    // else if (postType == 2)
                    postDB.loadPostByid(res[0] as any)
                    postDB.updateActiveTime(post.pid)
                    postDB.addOneSubpost(post)
                }
            })

            // TODO get @s and notification users
            notificationDB.addNotification(post.author, 'comment', String(post.pid), String(ctx.user.uid))
        }
        await next()
    }

    @AdminController.checkIsAdmin
    @validateQuery({
        start_time: 'dateTime?',
        end_time: 'dateTime?',
        user_id: 'int?',
        'subarea[]': {type: 'array_uint', required: false},
        'status[]': {type: 'array_uint', required: false}
    })
    static async getModeratePosts(ctx: Context, next: Next) {
        ctx.cd = 0
        ctx.msg = "???"
        // ctx.return = ctx.validatedParams
        let {start_time, end_time, user_id} = ctx.validatedParams
        let subareas = ctx.validatedParams['subarea[]']
        let statuses = ctx.validatedParams['status[]']
        // console.log(ctx.query);
        let posts = await postDB.getModeratePosts(start_time, end_time, user_id, subareas, statuses)
        ctx.return = posts

        await next()
    }

    @AdminController.checkIsAdmin
    static async deletePost(ctx: Context, next: Next) {
        let {aid} = ctx.query

        await knex('post').where('pid', aid)
            .update({deleted: true}).then((num) => {
                if (num > 0) {
                    ctx.cd = 0
                    ctx.msg = "文章删除成功"
                }
                else {
                    ctx.cd = 1
                    ctx.msg = "文章删除失败"
                }
            })
        next()
    }
    @UserController.checkLogin


    @validateQuery({
        pid: 'int',
        relationship: userPostRelationDB.relationships,
        value: 'string'
    })
    static async changeRelationship(ctx: Context, next: Next) {
        let {pid, relationship, value} = ctx.validatedParams
        value = !!value && value !== 'false';
        let flag = false
        if (value)
            flag = await userPostRelationDB.addRelation(ctx.user.uid, pid, relationship)
        else
            flag = await userPostRelationDB.removeRelation(ctx.user.uid, pid, relationship)
        if (flag) {
            ctx.cd = 0
            ctx.msg = "修改成功"
        } else {
            ctx.cd = 1
            ctx.msg = "修改失败"
        }
        next()
    }

    @AdminController.checkIsAdmin
    @validateQuery({
        'post[]': {type: 'array_uint', required: false},
        status: 'int'
    })
    static async changeStatus(ctx: Context, next: Next) {
        let {status} = ctx.validatedParams
        let posts = ctx.validatedParams['post[]']
        let cnt = 0
        if (posts && posts.length)
            await knex('posts').whereIn('pid', posts)
                .update({status}).then((num) => {
                    cnt += num
                })
        if (cnt > 0) {
            ctx.cd = 0
            ctx.msg = "状态修改成功"
        }
        else {
            ctx.cd = 1
            ctx.msg = "状态修改失败"
        }
        next()
    }
    // @validateQuery({
    //     paged: 'int?',
    //     posts_per_page: {type: 'int', required: false, max: 1000},
    //     subarea: 'int?',
    //     key: 'string',
    // })
    // static async searchPost(ctx: Context, next: Next) {
    //     let {paged, posts_per_page, subarea, key} = ctx.validatedParams
    //     paged ??= 1
    //     posts_per_page ??= 10

    //     let posts = await postDB.queryPosts(paged, posts_per_page, key, subarea)
    //     for (let post of posts as any) {
    //         if (typeof post === 'string')
    //             post = JSON.parse(post)
    //         await PostController.assemblePost(post, ['star'])
    //     }
    //     ctx.cd = 0
    //     ctx.msg = "查找成功"
    //     ctx.return = posts
    //     next()
    // }
}
